package heap

import (
	"jvm/classfile"
	. "jvm/typedef"
	"strings"
)

// **************************************************
type Field struct {
	classMember
	slotId             U4
	constantValueIndex U2
}

// private
func newFields(class *Class, fieldsInfo []classfile.Field) []Field {
	length := len(fieldsInfo)
	fields := make([]Field, length)
	for i := 0; i < length; i++ {
		fields[i] = Field{}
		fields[i].class = class
		fields[i].readInfo(&fieldsInfo[i])
		for _, attr := range fieldsInfo[i].Attributes() {
			if constantValue, ok := attr.(*classfile.AttributeConstantValue); ok {
				fields[i].constantValueIndex = constantValue.ConstantvalueIndex()
				break
			}

		}
	}
	return fields
}

func (self *Field) readInfo(fieldInfo *classfile.Field) {
	self.accessFlags = fieldInfo.AccessFlags()
	self.name = fieldInfo.GetName()
	self.descriptor = fieldInfo.GetDescriptor()
}

// getter
func (self *Field) SlotId() U4 {
	return self.slotId
}

// **************************************************
type Method struct {
	classMember
	maxStack  U2
	maxLocals U2
	code      []U1
	//参数所占变量槽个数
	argSlotCount U2
}

func newMethods(class *Class, methodInfo []classfile.Method) []Method {
	length := len(methodInfo)
	methods := make([]Method, length)
	for i := 0; i < length; i++ {
		methods[i] = Method{}
		codeAttr := methodInfo[i].AttributeCode()
		if codeAttr != nil {
			methods[i].maxStack = codeAttr.MaxStack()
			methods[i].maxLocals = codeAttr.MaxLocals()
			methods[i].code = codeAttr.Code()
		}
		methods[i].class = class
		methods[i].readInfo(&methodInfo[i])
		methods[i].calcArgSlotCount()
	}
	return methods

}

// 解析方法参数所占变量槽个数
func (self *Method) calcArgSlotCount() {
	descriptor := self.descriptor
	args := descriptor[1:strings.LastIndex(descriptor, ")")]
	count := U2(0)
	for i := 0; i < len(args); i++ {
		switch args[i] {
		case 'Z', 'B', 'S', 'C', 'I', 'F':
			count++
		case 'J', 'D':
			count += 2
		case 'L':
			count++
			i += strings.Index(args[i:], ";")
		case '[':
			count++
			j := i + 1
			for ; args[j] == '['; j++ {
			}
			i = j
			if args[j] == 'L' {
				i += strings.Index(args[i:], ";")
			}
		}
	}
	if !self.IsStatic() {
		count++
	}
	self.argSlotCount = count
}

func (self *Method) readInfo(methodInfo *classfile.Method) {
	self.accessFlags = methodInfo.AccessFlags()
	self.name = methodInfo.GetName()
	self.descriptor = methodInfo.GetDescriptor()
}

// getter
func (self *Method) Code() []U1 {
	return self.code
}
func (self *Method) MaxStack() U2 {
	return self.maxStack
}
func (self *Method) MaxLocals() U2 {
	return self.maxLocals
}
func (self *Method) ArgSlotCount() U2 {
	return self.argSlotCount
}

// **************************************************
type classMember struct {
	accessFlags U2
	descriptor  string
	name        string
	class       *Class
}

// classMember是否可以被class访问
// 1.classMember是public时,可以被访问
// 2.classMember是protected时,当class与classMember的class在同一包下或为classMember的class的子类时，可以被访问
// 3.classMember是缺省时,当class与classMember的class在同一包下，可以被访问
// 4.classMember是private时,当class与classMember的class相同时，可以被访问
func (self *classMember) IsAccessibleTo(class *Class) bool {
	if self.IsPublic() {
		return true
	} else if self.IsProtected() {
		return self.class.PackageName() == class.PackageName() || class.IsSubClassOf(self.class)
	} else if self.IsPrivate() {
		return self.class == class
	} else {
		return self.class.PackageName() == class.PackageName()
	}

}

// **************************************************
// getter
func (self *classMember) Class() *Class {
	return self.class
}
func (self *classMember) Descriptor() string {
	return self.descriptor
}
func (self *classMember) Name() string {
	return self.name
}

// **************************************************
// 访问标志
func (self *classMember) IsPublic() bool {
	return 0 != self.accessFlags&ACC_PUBLIC
}
func (self *classMember) IsPrivate() bool {
	return 0 != self.accessFlags&ACC_PRIVATE
}
func (self *classMember) IsProtected() bool {
	return 0 != self.accessFlags&ACC_PROTECTED
}
func (self *classMember) IsStatic() bool {
	return 0 != self.accessFlags&ACC_STATIC
}
func (self *classMember) IsFinal() bool {
	return 0 != self.accessFlags&ACC_FINAL
}
func (self *classMember) IsSynthetic() bool {
	return 0 != self.accessFlags&ACC_SYNTHETIC
}
func (self *classMember) IsAbstract() bool {
	return 0 != self.accessFlags&ACC_ABSTRACT
}
func (self *classMember) IsNative() bool {
	return 0 != self.accessFlags&ACC_NATIVE
}
